/*
   Copyright 2022 cmanlh

   Licensed under the Apache License, Version 2.0 (the "License");
   you may not use this file except in compliance with the License.
   You may obtain a copy of the License at

       http://www.apache.org/licenses/LICENSE-2.0

   Unless required by applicable law or agreed to in writing, software
   distributed under the License is distributed on an "AS IS" BASIS,
   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   See the License for the specific language governing permissions and
   limitations under the License.
*/
import JscFormatter from './formatter.js';

export default class JscDate {
    static ONE_DAY_IN_MILLISECONDS = 86400000;
    static ONE_HOUR_IN_MILLISECONDS = 3600000;
    static TIME_EXP_REGEXP = /^([-+]?\d+Y)?([-+]?\d+M)?([-+]?\d+D)?([-+]?\d+H)?$/i;

    static toDate(date) {
        var _date = null;
        if (typeof (date) == 'string') {
            var _temp = isNaN(+date) ? date : +date;
            _date = new Date(_temp);
        } else if (typeof (date) == 'number') {
            _date = new Date(date);
        } else {
            _date = date;
        }
        if (_date instanceof (Date) && !isNaN(_date.valueOf())) {
            return _date;
        } else {
            throw new Error("invalid date parameter.");
        }
    }

    static from(year, month, day) {
        let date = new Date('2022/02/02');
        date.setFullYear(year);
        date.setMonth(month);
        date.setDate(day);

        return date;
    }
}

if (!Date.prototype.isJscDate) {
    Date.prototype.isJscDate = true;

    Date.prototype.toMilliSeconds = function (onlyKeepDate = true) {
        var _date = this.getTime();

        if (onlyKeepDate) {
            return _date - (_date - 57600000) % JscDate.ONE_DAY_IN_MILLISECONDS;
        } else {
            return _date;
        }
    };

    Date.prototype.format = function (fmt) {
        var _fmt = fmt || 'yyyy-MM-dd';
        return JscFormatter.date(this, _fmt);
    };

    Date.prototype.plusHours = function (num, toMilliSeconds) {
        var milliseconds = this.toMilliSeconds(false) + num * JscDate.ONE_HOUR_IN_MILLISECONDS;
        if (toMilliSeconds) {
            return milliseconds;
        } else {
            return new Date(milliseconds);
        }
    };

    Date.prototype.plusDays = function (num, toMilliSeconds) {
        var milliseconds = this.toMilliSeconds(false) + num * JscDate.ONE_DAY_IN_MILLISECONDS;
        if (toMilliSeconds) {
            return milliseconds;
        } else {
            return new Date(milliseconds);
        }
    };

    Date.prototype.plusMonths = function (num, toMilliSeconds) {
        var _date = new Date(this.toMilliSeconds(false));
        _date.setMonth(_date.getMonth() + num);
        if (toMilliSeconds) {
            return _date.getTime();
        } else {
            return _date;
        }
    };

    Date.prototype.plusYears = function (num, toMilliSeconds) {
        var _date = new Date(this.toMilliSeconds(false));
        _date.setFullYear(_date.getFullYear() + num);
        if (toMilliSeconds) {
            return _date.getTime();
        } else {
            return _date;
        }
    };

    Date.prototype.diffDays = function (date) {
        return (this.toMilliSeconds(true) - date.toMilliSeconds(true)) / JscDate.ONE_DAY_IN_MILLISECONDS;
    };

    Date.prototype.compareTo = function (date) {
        return this.getTime() - date.getTime();
    }

    Date.prototype.maxDaysInThisMonth = function () {
        switch (this.getMonth()) {
            case 0:
            case 2:
            case 4:
            case 6:
            case 7:
            case 9:
            case 11: {
                return 31;
            }
            case 3:
            case 5:
            case 8:
            case 10: {
                return 30;
            }
            case 1: {
                let tmp = this.plusMonths(1);
                tmp.setDate(1);
                return tmp.plusDays(-1).getDate();
            }
        }
    };
}